package com.atguigu.tingshu.order.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.account.AccountFeignClient;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.delay.DelayMsgService;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.client.OrderFeignClient;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.account.AccountLockVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.weaver.ast.Or;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.Signature;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private UserFeignClient userFeignClient;
    @Autowired
    private AlbumFeignClient albumFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderDerateMapper orderDerateMapper;
    @Autowired
    private AccountFeignClient accountFeignClient;
    @Autowired
    private DelayMsgService delayMsgService;


    /**
     * 关单
     * @param valueOf
     */
    @Override
    public void orderCanncal(String orderNo) {
        //查询订单详情
        LambdaQueryWrapper<OrderInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(OrderInfo::getOrderNo,orderNo);
        OrderInfo orderInfo = orderInfoMapper.selectOne(lambdaQueryWrapper);
        if (orderInfo!=null && SystemConstant.ORDER_STATUS_UNPAID.equals(orderInfo.getOrderStatus())){
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
            orderInfo.setUpdateTime(new Date());
            orderInfoMapper.updateById(orderInfo);
        }
    }





    /**
     * 根据订单号获取订单相关信息
     * /api/order/orderInfo/getOrderInfo/{orderNo}
     */
    @Override
    public OrderInfo getOrderInfo(String orderNo) {
        //获取用户信息
        Long userId = AuthContextHolder.getUserId();
        LambdaQueryWrapper<OrderInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(OrderInfo::getUserId,userId);
        lambdaQueryWrapper.eq(OrderInfo::getOrderNo,orderNo);
        OrderInfo orderInfo = orderInfoMapper.selectOne(lambdaQueryWrapper);
        //获取订单明细信息
        LambdaQueryWrapper<OrderDetail> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
        lambdaQueryWrapper1.eq(OrderDetail::getOrderId,orderInfo.getId());
        List<OrderDetail> orderDetails = orderDetailMapper.selectList(lambdaQueryWrapper1);
        orderInfo.setOrderDetailList(orderDetails);
        //设置orderStatusName
        orderInfo.setOrderStatusName(this.setOrderStatusName(orderInfo.getOrderStatus()));
        //设置订单减免表
        LambdaQueryWrapper<OrderDerate> lambdaQueryWrapper2 = new LambdaQueryWrapper<>();
        lambdaQueryWrapper2.eq(OrderDerate::getOrderId,orderInfo.getId());
        List<OrderDerate> orderDerates = orderDerateMapper.selectList(lambdaQueryWrapper2);
        orderInfo.setOrderDerateList(orderDerates);
        //设置付款方式
        orderInfo.setPayWayName(this.setPayWayName(orderInfo.getPayWay()));

        return orderInfo;
    }

    /**
     * 获取我的订单
     * /api/order/orderInfo/findUserPage/1/10
     */
    @Override
    public Page<OrderInfo> findUserPage(Page<OrderInfo> page1, Long userId) {
        return orderInfoMapper.selectUserPage(page1,userId);
    }




    /**
     * 设置付款方式
     * @param payWay
     * @return
     */
    private String setPayWayName(String payWay) {
        if (SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(payWay)){
            return "微信";
        }else if (SystemConstant.ORDER_PAY_WAY_ALIPAY.equals(payWay)){
            return "支付宝";
        }else if (SystemConstant.ORDER_PAY_ACCOUNT.equals(payWay)){
            return "账户余额";
        }
        return "支付不详,联系客服";
    }

    /**
     * 根据状态编号返回对应名字
     * @return
     */
    private String setOrderStatusName(String orderStatus) {

        if (SystemConstant.ORDER_STATUS_UNPAID.equals(orderStatus)){
            return "未支付";
        }else if (SystemConstant.ORDER_STATUS_PAID.equals(orderStatus)){
            return "已支付";
        }else if (SystemConstant.ORDER_STATUS_CANCEL.equals(orderStatus)){
            return "已取消";
        }
        return "未知，请联系客服";
    }

    /**
     * 提交订单
     * /api/order/orderInfo/submitOrder
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)  //TODO 分布式事务问题
    public Map<String, String> submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //删除redis防止重复提交
        //定义key
        String tradeKey= RedisConstant.ORDER_TRADE_NO_PREFIX+ userId;
        //获取交易号
        String tradeNo = orderInfoVo.getTradeNo();
        //定义lua脚本
        String scritp = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        //定义lua脚本对象
        DefaultRedisScript<Boolean> defaultRedisScript = new DefaultRedisScript<Boolean>();
        defaultRedisScript.setScriptText(scritp);
        defaultRedisScript.setResultType(Boolean.class);

        //发送脚本到redis
        Boolean flag = (Boolean) redisTemplate.execute(defaultRedisScript, Arrays.asList(tradeKey), tradeNo);
        //判断
        if (!flag) {
            throw new GuiguException(400, "订单重复提交，请重新确认后提交。");
        }
        //防止提交的信息被篡改
        //获取提交的信息与之前的签名对比
        Map<String, Object> beanToMap = BeanUtil.beanToMap(orderInfoVo);
        //删除之前没有进行加密的
        beanToMap.remove("payWay");
        //传入加密并且判断是否一致
        SignHelper.checkSign(beanToMap);
        //保存订单
        OrderInfo orderInfo = this.saveOrder(orderInfoVo,userId);
        //获取支付方式
        String payWay = orderInfoVo.getPayWay();
        //如果为余额支付
        if (payWay.equals(SystemConstant.ORDER_PAY_ACCOUNT)){
            //扣减余额
            AccountLockVo accountLockVo =new AccountLockVo();
            accountLockVo.setOrderNo(orderInfo.getOrderNo());
            accountLockVo.setAmount(orderInfoVo.getOrderAmount());
            accountLockVo.setUserId(userId);
            accountLockVo.setContent(orderInfo.getOrderTitle());
            Result result = accountFeignClient.checkAndDeduct(accountLockVo);
            if (result.getCode()!=200){
                throw new GuiguException(400,"扣减余额出现错误");
            }
            //完成虚拟发货
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setOrderNo(orderInfo.getOrderNo());
            userPaidRecordVo.setUserId(userId);
            userPaidRecordVo.setItemType(orderInfoVo.getItemType());
            List<Long> collect = orderInfoVo.getOrderDetailVoList().stream().map(orderDetailVo -> orderDetailVo.getItemId()).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(collect);
            Result result1 = userFeignClient.savePaidRecord(userPaidRecordVo);

            if (result1.getCode()!=200){
                throw new GuiguException(400,"虚拟发货出现错误");
            }
            //修改订单状态
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
            orderInfo.setUpdateTime(new Date());
            orderInfoMapper.updateById(orderInfo);
        }
        Map<String, String> map = new HashMap<>();
        map.put("orderNo",orderInfo.getOrderNo());

        delayMsgService.sendDelayMessage(KafkaConstant.QUEUE_ORDER_CANCEL,orderInfo.getOrderNo(),Long.valueOf(KafkaConstant.DELAY_TIME));

        return map;
    }



    //保存订单
    private OrderInfo saveOrder(OrderInfoVo orderInfoVo, Long userId) {
        //复制数据
        OrderInfo orderInfo = BeanUtil.copyProperties(orderInfoVo, OrderInfo.class);
        //设置用户ID
        orderInfo.setUserId(userId);
        //设置订单标题
        String itemName = orderInfoVo.getOrderDetailVoList().get(0).getItemName();
        orderInfo.setOrderTitle(itemName);
        //设置订单号
        String orderNo = DateUtil.today().replaceAll("-", "") + IdUtil.getSnowflakeNextId();
        orderInfo.setOrderNo(orderNo);
        //设置支付状态
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        //保存订单表
        orderInfoMapper.insert(orderInfo);
        //保存详情表
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        if (CollectionUtil.isNotEmpty(orderDetailVoList)){
            //如果不等于空
            for (OrderDetailVo orderDetailVo : orderDetailVoList) {
                OrderDetail orderDetail = BeanUtil.copyProperties(orderDetailVo, OrderDetail.class);
                orderDetail.setOrderId(orderInfo.getId());
                orderDetailMapper.insert(orderDetail);
            }
        }
        //保存订单减免表
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if (CollectionUtil.isNotEmpty(orderDerateVoList)){
            for (OrderDerateVo orderDerateVo : orderDerateVoList) {
                OrderDerate orderDerate = BeanUtil.copyProperties(orderDerateVo, OrderDerate.class);
                orderDerate.setOrderId(orderInfo.getId());
                orderDerateMapper.insert(orderDerate);
            }
        }
        return orderInfo;
    }


    /**
     * 订单确认 订单结算
     * /api/order/orderInfo/trade
     * @return
     */
    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        //创建封装对象
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //获取付款项目类型
        String itemType = tradeVo.getItemType();
        //获取付款项目类型Id
        Long itemId = tradeVo.getItemId();
        //设置订单原始金额
        orderInfoVo.setOriginalAmount(new BigDecimal(0.00));
        //设置减免总金额
        orderInfoVo.setDerateAmount(new BigDecimal(0.00));
        //设置订单总金额
        orderInfoVo.setOrderAmount(new BigDecimal(0.00));
        //设置订单明细列表
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //设置订单减免明细列表
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        if (itemType.equals(SystemConstant.ORDER_ITEM_TYPE_VIP)){
            //1003-vip会员
            //根据用户选择的套餐查询套餐详情
            VipServiceConfig data = userFeignClient.getVipServiceConfig(itemId).getData();
            //判断
            Assert.notNull(data,"查询vip套餐异常，套餐id:{}",itemId);
            //获取原价 并存入
            BigDecimal price = data.getPrice();
            orderInfoVo.setOriginalAmount(price);
            //获取折后价 并存入
            BigDecimal discountPrice = data.getDiscountPrice();
            orderInfoVo.setOrderAmount(discountPrice);
            //减免总金额 并存入
            BigDecimal subtract = price.subtract(discountPrice);
            orderInfoVo.setDerateAmount(subtract);
            //创建订单减免明细封装对象
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
            orderDerateVo.setDerateAmount(subtract);
            orderDerateVo.setRemarks("VIP限时优惠：" + subtract);
            orderDerateVoList.add(orderDerateVo);
            //创建订单明细列表封装
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(itemId);
            orderDetailVo.setItemPrice(price);
            orderDetailVo.setItemUrl(data.getImageUrl());
            orderDetailVo.setItemName(data.getName());
            orderDetailVoList.add(orderDetailVo);

        }else if (itemType.equals(SystemConstant.ORDER_ITEM_TYPE_TRACK)){
            //1002-声音
            //查询用户待购买的声音列表
            List<TrackInfo> trackInfoList = albumFeignClient.findPaidTrackInfoList(itemId, tradeVo.getTrackCount()).getData();
            if (CollectionUtil.isEmpty(trackInfoList)){
                throw new GuiguException(400, "无符合要求声音");
            }
            //查看这个声音的单价
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId()).getData();
            BigDecimal price = albumInfo.getPrice();
            //计算价格
            BigDecimal originalAmount = price.multiply(new BigDecimal(trackInfoList.size()));
            orderInfoVo.setOriginalAmount(originalAmount);
            orderInfoVo.setOrderAmount(originalAmount);
            orderInfoVo.setDerateAmount(originalAmount.subtract(originalAmount));
            //创建订单明细列表封装
            for (TrackInfo trackInfo : trackInfoList) {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVo.setItemId(trackInfo.getId());
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                orderDetailVoList.add(orderDetailVo);
            }
        } else if (itemType.equals(SystemConstant.ORDER_ITEM_TYPE_ALBUM)) {
            //1001-专辑
            //判断该用户是否购买过这本专辑
            Boolean data = userFeignClient.isPaidAlbum(itemId).getData();
            if (data){
                throw new GuiguException(400,"已经购买过该专辑，请换一个");
            }
            //到这里说明是没有购买过这本专辑的
            //获取专辑信息
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(itemId).getData();
            //查询用户是不是vip,vip有会员价格，普通用户有普通用户的价格
            //获取用户信息
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            //获取原始金额
            BigDecimal price = albumInfo.getPrice();
            //订单价格是打折后的最终价格
            BigDecimal discountPrice = price;

            if (albumInfo.getDiscount().intValue() != -1){
                //进入说明普通用户打折
                //到这里有两种情况有vip没vip不一样
                if (userInfoVo.getIsVip()==0){
                    //这里说明不是vip
                    discountPrice = price.multiply(albumInfo.getDiscount()).divide(new BigDecimal(10),2, RoundingMode.HALF_UP);
                }else if (userInfoVo.getIsVip()==1 && new Date().after(userInfoVo.getVipExpireTime())){
                    //这里说明不是vip
                    discountPrice = price.multiply(albumInfo.getDiscount()).divide(new BigDecimal(10),2, RoundingMode.HALF_UP);
                }
            }

            //判断会员是否打折
            if (albumInfo.getVipDiscount().intValue() != -1){
                //进入说明打折
                //判断是否是vip
                if (userInfoVo.getIsVip() == 1 && new Date().before(userInfoVo.getVipExpireTime())){
                    discountPrice = discountPrice = price.multiply(albumInfo.getVipDiscount()).divide(new BigDecimal(10),2, RoundingMode.HALF_UP);
                }
            }
            //设置订单原始金额
            orderInfoVo.setOriginalAmount(price);
            //设置减免总金额
            BigDecimal subtract = price.subtract(discountPrice);
            orderInfoVo.setDerateAmount(subtract);
            //设置订单总金额
            orderInfoVo.setOrderAmount(discountPrice);
            //设置订单明细列表
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(itemId);
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVo.setItemPrice(albumInfo.getPrice());
            orderDetailVoList.add(orderDetailVo);
            //设置订单减免明细列表
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            orderDerateVo.setRemarks("专辑优惠："+subtract);
            orderDerateVo.setDerateAmount(subtract);
            orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
            orderDerateVoList.add(orderDerateVo);
        }
        //设置集合
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);

        //设置交易号
        String uuid = IdUtil.fastSimpleUUID();
        orderInfoVo.setTradeNo(uuid);
        //定义交易号存储key
        String tradeKey= RedisConstant.ORDER_TRADE_NO_PREFIX+ userId;
        //存储数据redis
        redisTemplate.opsForValue().set(tradeKey,uuid,5, TimeUnit.MINUTES);
        //设置付款项目类型
        orderInfoVo.setItemType(itemType);
        //设置时间戳
        orderInfoVo.setTimestamp(DateUtil.current());
        //加密
        Map<String, Object> map = BeanUtil.beanToMap(orderInfoVo, false, true);
        //生成标签
        String sign = SignHelper.getSign(map);
        //设置标签
        orderInfoVo.setSign(sign);

        return orderInfoVo;
    }

}
